package cache

import (
	"errors"
	"log"
	storage "ozonTest/internal/dal/cache"
	"ozonTest/internal/domain/comments/model"
	"sync"
	"time"
)

type commentsDAO struct {
	db *storage.Database
	mu sync.RWMutex
}

func NewCommentsRepo(db *storage.Database) *commentsDAO {
	return &commentsDAO{db: db}
}

func (c *commentsDAO) CreateComment(comment *model.Comment) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	post, postExists := c.db.Posts[comment.PostID]
	if !postExists {
		err := errors.New("post not found")
		log.Printf("Error: %v, PostID: %d", err, comment.PostID)
		return err
	}

	if !post.CommentsEnabled {
		err := errors.New("comments are disabled for this post")
		log.Printf("Error: %v, PostID: %d", err, comment.PostID)
		return err
	}

	comment.ID = len(c.db.Comments) + 1
	comment.CreatedAt = time.Now()
	c.db.Comments[comment.ID] = comment

	log.Printf("Comment created: %+v", comment)
	return nil
}

func (c *commentsDAO) CreateReply(parentID int, reply *model.Comment) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	parentComment, exists := c.db.Comments[parentID]
	if !exists {
		err := errors.New("parent comment not found")
		log.Printf("Error: %v, ParentID: %d", err, parentID)
		return err
	}

	reply.ID = len(c.db.Comments) + 1
	reply.ParentID = &parentID
	reply.CreatedAt = time.Now()
	c.db.Comments[reply.ID] = reply

	parentComment.Replies = append(parentComment.Replies, reply)

	log.Printf("Reply created: %+v", reply)
	return nil
}

func (c *commentsDAO) GetComment(id int) (*model.Comment, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	comment, exists := c.db.Comments[id]
	if !exists {
		err := errors.New("comment not found")
		log.Printf("Error: %v, CommentID: %d", err, id)
		return nil, err
	}

	log.Printf("Comment retrieved: %+v", comment)
	return comment, nil
}

func (c *commentsDAO) GetAllComments() ([]model.Comment, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	comments := make([]model.Comment, 0, len(c.db.Comments))
	for _, comment := range c.db.Comments {
		comments = append(comments, *comment)
	}

	log.Printf("All comments retrieved: %+v", comments)
	return comments, nil
}

func (c *commentsDAO) DeleteComment(id int) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	comment, exists := c.db.Comments[id]
	if !exists {
		err := errors.New("comment not found")
		log.Printf("Error: %v, CommentID: %d", err, id)
		return err
	}

	delete(c.db.Comments, id)
	log.Printf("Comment deleted: %+v", comment)

	if comment.ParentID == nil {
		return nil
	}

	parentComment, ok := c.db.Comments[*comment.ParentID]
	if !ok {
		err := errors.New("parent comment not found")
		log.Printf("Error: %v, ParentID: %d", err, *comment.ParentID)
		return err
	}

	var updatedReplies []*model.Comment
	for _, c := range parentComment.Replies {
		if c.ID != id {
			updatedReplies = append(updatedReplies, c)
		}
	}
	parentComment.Replies = updatedReplies

	log.Printf("Replies updated for parent comment: %+v", parentComment)
	return nil
}

func (c *commentsDAO) GetCommentsByPost(postID int) ([]*model.Comment, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	var rootComments []*model.Comment
	for _, comment := range c.db.Comments {
		if comment.PostID == postID && comment.ParentID == nil {
			rootComments = append(rootComments, comment)
		}
	}

	if len(rootComments) == 0 {
		err := errors.New("no comments found for the post")
		log.Printf("Error: %v, PostID: %d", err, postID)
		return nil, err
	}

	log.Printf("Comments retrieved for PostID %d: %+v", postID, rootComments)
	return rootComments, nil
}
